/*
 * Created by SharpDevelop.
 * User: Michael
 * Date: 6/11/2007
 * Time: 2:54 AM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;

namespace SudokuSolver
{
	/// <summary>
	/// Pairs is a passive technique which finds pairs of cells (within a group) with the same
	/// candidate values.
	/// These values are then eliminated from all other cells in the group.
	/// Note that this only works for "Naked Pairs". That is, cells that only have 2 candidates are valid in this kind of pair.
	/// </summary>
	public class Pairs : Technique
	{
		private bool FindPairs(Group group)
		{
			List<Cell> cellsWith2Candidates = new List<Cell>();
			foreach(Cell cell in group.Cells)
			{
				if(cell.CandidateList.Length == 2)
					cellsWith2Candidates.Add(cell);
			}
			
			Dictionary<string, List<Cell>> pairsList = new Dictionary<string, List<Cell>>();
			for(int i = 0; i < cellsWith2Candidates.Count; i++)
			{
				for(int j = i + 1; j < cellsWith2Candidates.Count; j++)
				{
					if(cellsWith2Candidates[i].CandidateList == cellsWith2Candidates[j].CandidateList)
					{
						List<Cell> thesePairs = new List<Cell>();
						thesePairs.Add(cellsWith2Candidates[i]);
						thesePairs.Add(cellsWith2Candidates[j]);
						if(!pairsList.ContainsKey(cellsWith2Candidates[i].CandidateList))
					   	{
					   		pairsList.Add(cellsWith2Candidates[i].CandidateList, thesePairs);
					   	} else {
					   		//the key already exists!
					   		//Something has gone wrong!
					   		throw new InvalidSudokuException("Candidate pair found twice in one group (ie: two numbers must fit in four cells)", this);
					   	}
					}
				}
			}
			
			bool changed = false;
			foreach(string key in pairsList.Keys)
			{
				List<Cell> pair = pairsList[key];
				if(pair.Count > 2)
				{
					throw new InvalidSudokuException("Two numbers are supposed to fit into "+ pair.Count.ToString() + " cells!", this);
				} else {
					if(pair.Count < 2)
					{
						//can't do anything, next pair
					} else {
						//pairCells.Count == 2
						//eliminate the candidates from the other cells
						//for each cell in the group
						
						int[] candidates = new int[2];
						for(int i = 0; i < candidates.Length; i++)
							candidates[i] = int.Parse(key[i].ToString());
						foreach(Cell cell in group.Cells)
						{
							//if they aren't one of the pair
							if(!pair.Contains(cell))
							{
								foreach(int candidate in candidates)
								{
									if(cell.IsPossible(candidate))
									{
										cell.IsPossible(candidate, false);
										changed = true;
									}
								}
							}
						}
					}
					
				}
			}
			return changed;
		}
		
		public override bool Run(SudokuGame theGame)
		{
			bool changed = false;
			foreach(Group row in theGame.Rows)
			{
				if(FindPairs(row))
					changed = true;
			}
			
			foreach(Group column in theGame.Columns)
			{
				if(FindPairs(column))
					changed = true;
			}
			
			foreach(Group block in theGame.Blocks)
			{
				if(FindPairs(block))
					changed = true;
			}
			
			return changed;
		}
		
		public override string ToString()
		{
			return base.ToString() + ": Pairs";
		}
	}
}
